home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
util
/
arc
/
dmscheck.lha
/
dmscheck.c
Wrap
C/C++ Source or Header
|
1991-08-23
|
14KB
|
592 lines
/*
* DMS-check: by ????????, the unknown programmer
*
* This is a program for checking "dms" files on unix systems.
* Its usage is:
dmscheck <option> files ...
*
* Options are:
-h or -? : little help
-s : silent mode. No output at all, only status returned.
-v : verbose mode. Gives the content of the file.
-d : debug mode. Very verbose.
* In standart mode, you only get a message "FILE GOOD" or "FILE BAD"
* for each file you specify.
* The code is pretty basic Unix, there should be no compiling problem,
* just do "cc dmscheck.c -o dmscheck" to get the executable.
* Care was taken to read and use the data as char arrays to avoid
* alignement problems inside structures (a main portability nuisance).
*
* NB: People with little endian machines should define LITTLEINDIAN below.
* If you're not sure then try out normally. If it fails/coredumps, try with
* debug flag (-d) and see if CRC's are backwards. If yes: define it.
* [little-endian compatibility by Geoff C. Wing (gwing@mullauna.cs.mu.oz.au)]
* that's right, blame it on me if it doesn't work anymore for big-endians :-)
*
* TODO: a bit more error checking, I reckon.
*/
/* #define LITTLEINDIAN /* for little-endian machines */
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#define BOXSIZE 5
#define MAXTRACKS 85
typedef char BYTE;
typedef unsigned char UBYTE;
typedef short SHORT;
typedef unsigned short USHORT;
typedef long LONG;
typedef unsigned long ULONG;
#define SILENT 0
#define NORMAL 1
#define VERBOSE 2
#define DEBUG 3
int MessageLevel = NORMAL ;
#define NOERROR 0
#define NONFATAL 1
#define FATAL 2
int BadFileFlag = 0 ;
int GlobalStatus = 0 ;
int FirstTrack = 0 ;
int LastTrack = 0 ;
char Tracks[MAXTRACKS] ;
char IoBuf[60000] ;
USHORT Crc ;
/* Format of a simple DMS file:
Ident File_Head CRC Track_Head CRC Data Track_Head CRC Data ....
*/
char Ident[6] ; /* "DMS!" */
/*
These macros are used to access the file header components
with no concern about the alignement requirements of each machine.
*/
#ifdef LITTLEINDIAN
#define little_swap_short(a) (((a & 0x00ff) << 8) \
+ ((a & 0xff00) >> 8))
#define little_swap_long(a) (((a & 0x000000ff) << 24) \
+ ((a & 0x0000ff00) << 8) \
+ ((a & 0x00ff0000) >> 8) \
+ ((a & 0xff000000) >> 24))
#else /* not LITTLEINDIAN */
#define little_swap_short(a) (a)
#define little_swap_long(a) (a)
#endif /* not LITTLEINDIAN */
#define DHEAD_FROM(tab) (SHORT)little_swap_short(*((SHORT *) (tab+12)))
#define DHEAD_TO(tab) (SHORT)little_swap_short(*((SHORT *) (tab+14)))
#define DHEAD_CSIZE(tab) (ULONG)little_swap_long(*((ULONG *) (tab+16)))
#define DHEAD_SIZE(tab) (ULONG)little_swap_long(*((ULONG *) (tab+20)))
#define DHEAD_MODE(tab) (SHORT)little_swap_short(*((SHORT *) (tab+48)))
char DHeader[50] ;
struct File_Head /*offset - sizeof(File_Head) = 50 */
{
long u1 ; /* 0 - ???? */
long u2 ; /* 4 - ???? */
long date ; /* 8 - Creation date of file */
short from ; /*12 - index of first track */
short to ; /*14 - index of last track */
ULONG size_after ; /*16 - total size of data after compression */
ULONG size_before ; /*20 - total size of data before compression */
long u3 ; /*24 - 0 */
short cpu ; /*28 - Cpu type ( 1:68000, 2:68010, ... ) */
short copross ; /*30 - Cpu coprocessor ( 1:68881 ) */
short machine ; /*32 - Machine used ( 1:Amiga, 2:PC, ...) */
short u4 ; /*34 - ??? */
short cpu_speed ; /*36 - */
long time ; /*38 - Time to create archive in sec. */
short c_version ; /*42 - Version of creator (66, 67, 68) */
short n_version ; /*44 - Version needed to extract */
short disk_type ; /*46 - Disktype of archive */
short cmode ; /*48 - compression mode 0-4 */
} ;
char THeader[18] ;
#define THEAD_IDENT(tab) (USHORT)little_swap_short(*((USHORT *) (tab+0 )))
#define THEAD_TNUM(tab) (SHORT)little_swap_short(*((SHORT *) (tab+2 )))
#define THEAD_SIZE(tab) (ULONG)little_swap_long(*((ULONG *) (tab+4 )))
#define THEAD_DCRC(tab) (USHORT)little_swap_short(*((USHORT *) (tab+16)))
struct Track_Head /*offset - sizeof(Track_Head) = 18 */
{
short delim ; /* 0 - delimiter, 0x5452, is 'TR' */
short number ; /* 2 - track number, -1 if text */
ULONG size ; /* 4 - size of data part */
USHORT plength ; /* 8 - length of non-encoded data */
USHORT ulength ; /*10 - length of encoded data */
short mode ; /*12 - encryption mode(0: simple, 102: quick)*/
USHORT usum ; /*14 - raw data checksum */
USHORT dcrc ; /*16 - data CRC */
} ;
static USHORT CRCTab[256]=
{
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};
USHORT DoBlockCRC(Mem, Size)
UBYTE* Mem;
int Size ;
{
register USHORT CRC = 0;
while(Size--)
CRC = CRCTab[((CRC ^ *Mem++) & 255)] ^ ((CRC >> 8) & 255);
return (CRC) ;
}
#define MAXFILES 250
char * ListOfFiles[MAXFILES] ;
int NumberOfFiles ;
static void AppendFileName(f)
char * f;
{
if ( NumberOfFiles >= MAXFILES )
{
printf("\tToo many files. Max is %d\n",MAXFILES) ;
exit(1) ;
}
else
{
ListOfFiles[NumberOfFiles++] = f ;
}
}
static void ReadError(s,n)
char* s;
int n;
{
if ( MessageLevel >= VERBOSE )
printf("\tError reading %s (%d char read)\n",s,n) ;
}
static void WhereInFile(fd,s)
int fd ;
char *s;
{
int init;
init = lseek(fd, 0L, L_INCR) ;
if ( MessageLevel >= DEBUG )
printf("\tStarting read of %s at offset %d\n",s,(int) init ) ;
}
/*
* Handling track data
*
*/
static void ReadTrackHeader(fd)
int fd ;
{
int n_read ;
WhereInFile(fd,"Track header") ;
n_read = read(fd, THeader, sizeof(THeader) ) ;
if ( n_read != sizeof(THeader) )
{
ReadError("Theader DATA",n_read) ;
BadFileFlag = FATAL;
return;
}
n_read = read(fd, (char *) &Crc, 2) ;
if ( n_read != 2 )
{
ReadError("THeader CRC",n_read) ;
BadFileFlag = FATAL;
}
Crc = little_swap_short(Crc);
}
static void VerifyTrackHeader()
{
USHORT crc ;
if ( THEAD_IDENT(THeader) != 0x5452 ) /* Magic string "TR" */
{
if ( MessageLevel >= VERBOSE )
printf("\tBAD THeader identifier: %4x\n",
(int) THEAD_IDENT(THeader) );
BadFileFlag = FATAL ;
return ;
}
crc = DoBlockCRC( THeader, sizeof(THeader) ) ;
if ( crc != Crc )
{
if ( MessageLevel >= VERBOSE )
printf("\tBAD THeader checksum. Read %4x, computed %4x\n",
(int) Crc, (int) crc ) ;
BadFileFlag = FATAL ; /* size is not sure */
}
else if ( MessageLevel >= DEBUG )
printf("\tTrack Header checksum OK (%4x)\n",(int) crc ) ;
}
static void ReadTrackData(fd)
int fd ;
{
int n_read ;
if ( MessageLevel >= DEBUG )
printf("\tSize of track data: %d\n", (int) THEAD_SIZE(THeader) );
n_read = read(fd, IoBuf, (int) THEAD_SIZE(THeader)) ;
if ( n_read != THEAD_SIZE(THeader) )
{
ReadError("track data",n_read) ;
BadFileFlag = FATAL ;
return;
}
}
static void VerifyTrackData()
{
USHORT crc ;
crc = DoBlockCRC( IoBuf, (int) THEAD_SIZE(THeader) );
if ( crc != THEAD_DCRC(THeader) )
{
if ( MessageLevel >= VERBOSE )
{
printf("\tTrack: %2d ", (int) THEAD_TNUM(THeader)) ;
printf("-BAD CRC: read %4x, computed %4x\n",
(int) THEAD_DCRC(THeader), (int) crc ) ;
}
BadFileFlag = NONFATAL ;
}
else if ( MessageLevel >= VERBOSE )
{
printf("\tTrack: %2d ", (int) THEAD_TNUM(THeader)) ;
printf("-GOOD CRC: %4x\n",(int) crc ) ;
}
}
static void UpdateTrackCount()
{
Tracks[(int) THEAD_TNUM(THeader)] = 1 ;
}
static void TreatTrackHunk(fd)
int fd ;
{
ReadTrackHeader(fd) ;
if ( BadFileFlag != FATAL )
VerifyTrackHeader() ;
if ( BadFileFlag != FATAL )
ReadTrackData(fd) ;
if ( BadFileFlag != FATAL )
VerifyTrackData() ;
if ( BadFileFlag != FATAL )
UpdateTrackCount() ;
}
static int MoreTrackToRead()
{
return (( Tracks[LastTrack] ) ? 0 : 1) ;
}
static void TreatTracks(fd)
int fd ;
{
while ( BadFileFlag != FATAL && MoreTrackToRead() )
TreatTrackHunk(fd) ;
}
static void InitialiseTrackData()
{
int i;
BadFileFlag = 0 ;
for ( i= 0; i< MAXTRACKS; i++ )
Tracks[i] = 0 ;
}
/*
* Handling one file dms header
*
*/
void VerifyDHeader()
{
USHORT crc ;
if ( strncmp(Ident, "DMS!", 4 ) )
{
if ( MessageLevel >= NORMAL )
printf("\tThis is *not* a dms archive\n") ;
BadFileFlag = FATAL ;
return;
}
crc = DoBlockCRC(DHeader, sizeof(DHeader) ) ;
if ( crc != Crc )
{
if ( MessageLevel >= VERBOSE )
printf("\tBAD file header checksum. Read %4x, computed %4x\n",
(int) Crc, (int) crc) ;
BadFileFlag = FATAL ;
}
else if ( MessageLevel >= DEBUG )
printf("\tDms Header checksum OK (%4x = %4x)\n",
(int) crc, (int) Crc );
}
static void UpdateFileData()
{
if ( MessageLevel >= VERBOSE )
{
printf("\tContains tracks: %d to %d\n",
(int) DHEAD_FROM(DHeader), (int) DHEAD_TO(DHeader) );
printf("\tCompression mode: %d\n", (int) DHEAD_MODE(DHeader)) ;
printf("\tData sizes: raw: %d compressed: %d\n",
(int) DHEAD_SIZE(DHeader), (int) DHEAD_CSIZE(DHeader));
}
FirstTrack = (int) DHEAD_FROM(DHeader) ;
LastTrack = (int) DHEAD_TO(DHeader) ;
}
void ReadDHeader(fd)
int fd ;
{
int n_read ;
WhereInFile(fd,"Ident") ;
n_read = read(fd, Ident, 4) ;
if ( n_read < 4 )
{
ReadError("Ident",n_read) ;
BadFileFlag = FATAL ;
return ;
}
WhereInFile(fd,"DHeader") ;
n_read = read(fd, DHeader, sizeof(DHeader)) ;
if ( n_read < sizeof(DHeader) )
{
ReadError("DHeader DATA",n_read) ;
BadFileFlag = FATAL ;
return ;
}
n_read = read(fd, (char *) &Crc, 2) ;
if ( n_read < 2 )
{
ReadError("DHeader CRC",n_read) ;
BadFileFlag = FATAL ;
}
Crc = little_swap_short(Crc);
}
void TreatDHeader(fd)
int fd ;
{
ReadDHeader(fd) ;
if ( BadFileFlag != FATAL )
VerifyDHeader() ;
if ( BadFileFlag != FATAL )
UpdateFileData() ;
}
/*
* Handling one file
*
*/
static void TreatFile(file_)
char * file_ ;
{
int fd ;
if ( (fd = open(file_, 0)) == -1 )
{
fprintf(stderr,"\tError opening file: %s\n", file_) ;
return ;
}
if ( NumberOfFiles > 1 && MessageLevel >= NORMAL )
printf("Treating file: %s\n", file_ ) ;
InitialiseTrackData() ;
TreatDHeader(fd) ;
if ( BadFileFlag != FATAL )
TreatTracks(fd) ;
if ( BadFileFlag )
{
if ( MessageLevel >= NORMAL )
printf("\t>>> FILE BAD\n") ;
GlobalStatus = 1 ;
}
else if ( MessageLevel >= NORMAL )
printf("\t>>> FILE GOOD\n" ) ;
close(fd) ;
}
/*
* Various intialisations and command line handle
*
*/
static PrintHelp()
{
puts("Valid options are:") ;
puts("\t-s : silent") ;
puts("\t-v : verbose") ;
puts("\t-d : debug (very verbose)") ;
puts("\t-h,-? : help") ;
exit(0) ;
}
static int DecodeOption(argv, arg)
char * argv[] ;
int arg ;
{
char *argp = argv[arg]+1 ;
switch ( *argp )
{
case 's':
MessageLevel = SILENT ;
return (arg+1) ;
case 'v':
MessageLevel = VERBOSE ;
return (arg+1) ;
case 'd':
MessageLevel = DEBUG ;
return (arg+1) ;
case 'h':
case '?':
default:
PrintHelp() ;
return (arg+1) ; /* Not executed */
}
}
void DecodeArgLine(argc, argv)
int argc ;
char * argv[] ;
{
int arg ;
if ( argc <= 1)
{
PrintHelp() ;
}
for ( arg = 1; arg < argc ; )
{
if ( *argv[arg] != '-' )
{
AppendFileName(argv[arg]) ;
arg += 1 ;
}
else
arg = DecodeOption(argv,arg) ;
}
}
/*
* Main part
*
*/
int main(argc,argv)
int argc ;
char ** argv ;
{
int i;
DecodeArgLine(argc, argv) ;
for ( i=0 ; i< NumberOfFiles; i++ )
{
TreatFile(ListOfFiles[i]) ;
}
return ( GlobalStatus ) ;
}